// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/media/html_audio_element_capturer_source.h"

#include "base/threading/thread_task_runner_handle.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_sink.h"
#include "media/blink/webaudiosourceprovider_impl.h"
#include "media/blink/webmediaplayer_impl.h"
#include "third_party/WebKit/public/platform/WebMediaPlayer.h"

namespace content {

//static
HtmlAudioElementCapturerSource*
HtmlAudioElementCapturerSource::CreateFromWebMediaPlayerImpl(
    blink::WebMediaPlayer* player)
{
    DCHECK(player);
    return new HtmlAudioElementCapturerSource(
        static_cast<media::WebAudioSourceProviderImpl*>(
            player->getAudioSourceProvider()));
}

HtmlAudioElementCapturerSource::HtmlAudioElementCapturerSource(
    media::WebAudioSourceProviderImpl* audio_source)
    : MediaStreamAudioSource(true /* is_local_source */)
    , audio_source_(audio_source)
    , is_started_(false)
    , last_sample_rate_(0)
    , last_num_channels_(0)
    , last_bus_frames_(0)
{
    DCHECK(audio_source_);
}

HtmlAudioElementCapturerSource::~HtmlAudioElementCapturerSource()
{
    DCHECK(thread_checker_.CalledOnValidThread());
    EnsureSourceIsStopped();
}

bool HtmlAudioElementCapturerSource::EnsureSourceIsStarted()
{
    DCHECK(thread_checker_.CalledOnValidThread());
    if (audio_source_ && !is_started_) {
        // base:Unretained() is safe here since EnsureSourceIsStopped() guarantees
        // no more calls to OnAudioBus().
        audio_source_->SetCopyAudioCallback(base::Bind(
            &HtmlAudioElementCapturerSource::OnAudioBus, base::Unretained(this)));
        is_started_ = true;
    }
    return is_started_;
}

void HtmlAudioElementCapturerSource::EnsureSourceIsStopped()
{
    DCHECK(thread_checker_.CalledOnValidThread());
    if (!is_started_)
        return;

    if (audio_source_) {
        audio_source_->ClearCopyAudioCallback();
        audio_source_ = nullptr;
    }
    is_started_ = false;
}

void HtmlAudioElementCapturerSource::OnAudioBus(
    std::unique_ptr<media::AudioBus> audio_bus,
    uint32_t frames_delayed,
    int sample_rate)
{
    const base::TimeTicks capture_time = base::TimeTicks::Now() - base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond * frames_delayed / sample_rate);

    if (sample_rate != last_sample_rate_ || audio_bus->channels() != last_num_channels_ || audio_bus->frames() != last_bus_frames_) {
        MediaStreamAudioSource::SetFormat(
            media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                media::GuessChannelLayout(audio_bus->channels()),
                sample_rate, 16, audio_bus->frames()));
        last_sample_rate_ = sample_rate;
        last_num_channels_ = audio_bus->channels();
        last_bus_frames_ = audio_bus->frames();
    }

    MediaStreamAudioSource::DeliverDataToTracks(*audio_bus, capture_time);
}

} // namespace content
